package com.cmc.cloud.cmclink.doc.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.lock.annotation.Lock4j;
import com.cmc.cloud.cmclink.doc.constants.errorconstant.VoyageBsaPodErrorCodeConstants;
import com.cmc.cloud.cmclink.doc.entity.VoyageBsaDO;
import com.cmc.cloud.cmclink.doc.mapper.VoyageBsaMapper;
import com.cmc.cloud.cmclink.doc.vo.voyagebsapodvo.VoyageBsaPodBaseVO;
import com.cmc.cloud.cmclink.doc.vo.voyagebsapodvo.VoyageBsaPodCreateReqVO;
import com.cmc.cloud.cmclink.doc.vo.voyagebsapodvo.VoyageBsaPodPageReqVO;
import com.cmc.cloud.cmclink.doc.vo.voyagebsapodvo.VoyageBsaPodUpdateReqVO;
import com.cmes.framework.mybatis.core.query.LambdaQueryWrapperX;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import com.cmes.framework.common.pojo.PageResult;
import com.cmes.framework.common.exception.util.ServiceExceptionUtil;

import java.util.*;

import com.cmc.cloud.cmclink.doc.service.VoyageBsaPodService;
import com.cmc.cloud.cmclink.doc.entity.VoyageBsaPodDO;
import com.cmc.cloud.cmclink.doc.mapper.VoyageBsaPodMapper;


/**
 * 目的港舱位分配 Service 实现类
 *
 * @author 招商轮船-管理员
 */
@Service
@Validated
public class VoyageBsaPodServiceImpl implements VoyageBsaPodService {

    @Resource
    private VoyageBsaPodMapper voyageBsaPodMapper;

    @Resource
    private VoyageBsaMapper voyageBsaMapper;

    @Override
    @Transactional(rollbackFor = Exception.class)
    @Lock4j(name = "voyageBsaPodUnique", keys = {"#createReqVO.getPodCodes", "#createReqVO.getVoyageBsaId"})
    public void createVoyageBsaPod(VoyageBsaPodCreateReqVO createReqVO) {
        // 插入
        validateUniqueExists(createReqVO, null);
        VoyageBsaPodDO voyageBsaPod = BeanUtil.copyProperties(createReqVO, VoyageBsaPodDO.class);
        voyageBsaPodMapper.insert(voyageBsaPod);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @Lock4j(name = "voyageBsaPodUnique", keys = {"#updateReqVO.getPodCodes", "#updateReqVO.getVoyageBsaId"})
    public void updateVoyageBsaPod(VoyageBsaPodUpdateReqVO updateReqVO) {
        // 校验存在
        validateVoyageBsaPodExists(updateReqVO.getId());
        validateUniqueExists(updateReqVO, updateReqVO.getId());
        // 更新
        VoyageBsaPodDO updateObj = BeanUtil.copyProperties(updateReqVO, VoyageBsaPodDO.class);
        voyageBsaPodMapper.updateById(updateObj);
    }

    @Override
    public void deleteVoyageBsaPod(Long id) {
        // 校验存在
        validateVoyageBsaPodExists(id);
        // 删除
        voyageBsaPodMapper.deleteById(id);
    }

    private void validateVoyageBsaPodExists(Long id) {
        if (voyageBsaPodMapper.selectById(id) == null) {
            throw ServiceExceptionUtil.exception(VoyageBsaPodErrorCodeConstants.VOYAGE_BSA_POD_NOT_EXISTS);
        }
    }

    private void validateUniqueExists(VoyageBsaPodBaseVO vo, Long id) {
        VoyageBsaDO voyageBsaDO = voyageBsaMapper.selectById(vo.getVoyageBsaId());
        if (voyageBsaDO == null) {
            throw ServiceExceptionUtil.exception(VoyageBsaPodErrorCodeConstants.VOYAGE_BSA_POD_NOT_EXISTS);
        }
        //数量校验
        List<VoyageBsaPodDO> voyageBsaPodDos = voyageBsaPodMapper.selectList(new LambdaQueryWrapperX<VoyageBsaPodDO>()
                .eq(VoyageBsaPodDO::getVoyageBsaId, vo.getVoyageBsaId())
                .neIfPresent(VoyageBsaPodDO::getId, id));
        int sum = voyageBsaPodDos.stream().mapToInt(entity -> entity.getBsaTeu()).sum();
        if (Math.addExact(sum, vo.getBsaTeu()) > voyageBsaDO.getBsaTeu()) {
            throw ServiceExceptionUtil.exception(VoyageBsaPodErrorCodeConstants.VOYAGE_BSA_NUMBER_ERROR);
        }
        //重复校验
        LambdaQueryWrapperX<VoyageBsaPodDO> queryWrapperX = new LambdaQueryWrapperX<VoyageBsaPodDO>()
                .eqIfPresent(VoyageBsaPodDO::getVoyageBsaId, vo.getVoyageBsaId())
                .eqIfPresent(VoyageBsaPodDO::getPodCodes, vo.getPodCodes());
        if (id != null) {
            queryWrapperX.ne(VoyageBsaPodDO::getId, id);
        }
        if (voyageBsaPodMapper.selectCount(queryWrapperX) != 0L) {
            throw ServiceExceptionUtil.exception(VoyageBsaPodErrorCodeConstants.VOYAGE_BSA_POD_EXISTED);
        }
    }

    @Override
    public VoyageBsaPodDO getVoyageBsaPod(Long id) {
        return voyageBsaPodMapper.selectById(id);
    }

    @Override
    public List<VoyageBsaPodDO> getVoyageBsaPodByMainId(Long voyageBsaId) {
        return voyageBsaPodMapper.selectList(new LambdaQueryWrapperX<VoyageBsaPodDO>().eq(VoyageBsaPodDO::getVoyageBsaId, voyageBsaId));
    }

    @Override
    public List<VoyageBsaPodDO> getVoyageBsaPodList(Collection<Long> ids) {
        return voyageBsaPodMapper.selectBatchIds(ids);
    }

    @Override
    public PageResult<VoyageBsaPodDO> getVoyageBsaPodPage(VoyageBsaPodPageReqVO reqVO) {
        LambdaQueryWrapperX<VoyageBsaPodDO> queryWrapperX = new LambdaQueryWrapperX<>();
        return voyageBsaPodMapper.selectPage(reqVO, queryWrapperX);
    }
}
